import React, { useRef, useState, useEffect } from 'react';
import tinymce from 'tinymce';

// TinyMCE wants to be in global scope, even if loaded from npm module
window['tinymce'] = tinymce;
import { Editor } from '@tinymce/tinymce-react';
import { Editor as TinyMCEEditor } from 'tinymce';
// We're manually importing theme, icons and plugins because otherwise TinyMCE tries to resolve
// them himself and load throught http, but this won't work with chrome extension
// Theme
import 'tinymce/themes/silver/theme.min.js';
import 'tinymce/models/dom/model.js';
import 'tinymce/icons/default/icons.js';
import 'tinymce/skins/ui/oxide/skin.min.css';
import 'tinymce/skins/ui/oxide/content.inline.min.css';

import './styles/tinymce.css';
import styled from '@emotion/styled';

const ZCO_TAG = `<span class="mceNonEditable">ZCO_TAG_TEXT1<span class="mce-hide">ZCO_TAG_TEXT2</span>}}</span>`;
const ZCO_BEGIN_TAG = `&#xFEFF;`; // '\u00A0' `\n`
const ZCO_END_TAG = `\u00A0`; // '\u00A0' `\n`

interface TinymceTextareaProps {
	value: string;
	id: string;
	insertText: string;
	showCount?: boolean;
	maxLength?: number;
	placeholder?: string;
	disabled?: boolean;
	onChange?: (value: string) => void;
}

const TTSTextArea = styled.div`
	position: relative;
`;

export default function TinymceTextarea(props: TinymceTextareaProps) {
	const { value, showCount, maxLength, placeholder = '', id, insertText, disabled = false, onChange } = props;
	const [count, setCount] = useState(0);
	//   const [editorText, setEditorText] = useState<string>("");
	const editorRef = useRef<TinyMCEEditor | null>(null);

	useEffect(() => {
		if (insertText && editorRef.current) {
			let tag = formatTag(insertText);
			editorRef.current.execCommand('mceInsertContent', false, tag);
		}
	}, [insertText]);

	const formatTag = (text: string) => {
		let tag = ZCO_TAG;
		let subs = text.split('_');
		const text2 = '_' + subs[subs.length - 1].split('}')[0];
		subs.splice(subs.length - 1, 1);
		let text1 = subs.join('_');
		tag = tag.replace(/ZCO_TAG_TEXT1/g, text1);
		tag = tag.replace(/ZCO_TAG_TEXT2/g, text2);
		return tag;
	};

	const handleInit = (evt: any, editor: TinyMCEEditor) => {
		editorRef.current = editor;
		setCount(editor.getContent({ format: 'text' }).length);
		editor.on('keydown', handleKeyPress);
		editor.on('keyup', handleKeyPress);
	};

	const handleUpdate = (value: string, editor: TinyMCEEditor) => {
		const length = editor.getContent({ format: 'text' }).length;
		if (maxLength && length <= maxLength) {
			//   setEditorText(value);
			setCount(length);
			onChange && onChange(value);
		}
	};

	const handleBeforeAddUndo = (evt: any, editor: TinyMCEEditor) => {
		const length = editor.getContent({ format: 'text' }).length;
		// note that this is the opposite test as in handleUpdate
		// because we are determining when to deny adding an undo level
		if (maxLength && length > maxLength) {
			evt.preventDefault();
		}
	};

	const findNextEditableNode = (node: Node, next: boolean) => {
		let currentNode = next ? node.nextSibling : node.previousSibling; // nextSibling
		while (currentNode) {
			if (currentNode.nodeType === 3 && currentNode['tagName'] !== 'SPAN') {
				return currentNode;
			}
			currentNode = next ? currentNode.nextSibling : currentNode.previousSibling;
		}

		return null;
	};

	const handleKeyPress = (e: any) => {
		if (!editorRef.current) return;
		if (e.keyCode === 13) {
			e.preventDefault();
			e.stopPropagation();
			e.stopImmediatePropagation();
			return false;
		}
		if ([37, 39].includes(e.keyCode) && editorRef.current.selection.getNode().tagName === 'SPAN') {
			// 左箭头按键的键码
			e.preventDefault(); // 阻止默认行为
			e.stopPropagation();
			e.stopImmediatePropagation();
			// 找到下一个可编辑的节点
			const next = e.keyCode === 39;
			const nextEditableNode = findNextEditableNode(editorRef.current.selection.getNode(), next);

			if (nextEditableNode) {
				editorRef.current.selection.setCursorLocation(nextEditableNode, next ? 0 : nextEditableNode.textContent?.length || 0);
				return false;
			} else if (next) {
				const node = editorRef.current.selection.getNode().parentNode;
				if (node) {
					editorRef.current.selection.setCursorLocation(node, node.childNodes.length);
					editorRef.current.execCommand('mceInsertContent', false, ZCO_END_TAG);
					editorRef.current.execCommand('mceInsertContent', false, ZCO_BEGIN_TAG);
					editorRef.current.selection.setCursorLocation(node, node.childNodes.length);
				}
				return false;
			} else {
				const node = editorRef.current.selection.getNode();
				if (node && node.parentNode) {
					editorRef.current.selection.setCursorLocation(node.parentNode, 0);
					editorRef.current.execCommand('mceInsertContent', false, ZCO_BEGIN_TAG);
				}
				return false;
			}
		}
	};

	const handleonKeyDown = (e: any) => {
		if (!editorRef.current) return;
		if (e.keyCode === 13) {
			e.preventDefault();
			e.stopPropagation();
			e.stopImmediatePropagation();
			return false;
		}
	};

	return (
		<TTSTextArea>
			<Editor
				id={id}
				inline={true}
				// tinymceScriptSrc={window.location.origin + "/tinymce/tinymce.min.js"}
				// onInit={(evt, editor) => (editorRef.current = editor)}
				onInit={handleInit}
				// initialValue={value}
				value={value}
				init={{
					// selector: 'textarea',  // change this value according to your HTML
					height: 200,
					min_height: 200,
					menubar: false,
					plugins: [], // wordcount
					toolbar: false,
					inline: true,
					tagName: 'div',
					content_style: '',
					noneditable_class: 'mceNonEditable',
					placeholder: placeholder,
					// skin: false,
					// content_css: false,
					paste_block_drop: true,
					auto_focus: true
				}}
				onEditorChange={handleUpdate}
				onBeforeAddUndo={handleBeforeAddUndo}
				onKeyDown={handleonKeyDown}
				onKeyUp={handleonKeyDown}
				disabled={disabled}
			/>
			{showCount && maxLength && (
				<div className="mce-count-wrapper">
					<span>{count}</span>
					{' / '}
					<span>{maxLength}</span>
				</div>
			)}
		</TTSTextArea>
	);
}
